/*
 * Change Logs:
 * Date           Author       Notes
 * 2022-06-20     wyj          1.1.0增加修正温度为0时，采用外部温湿压传感器
 * */

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include <easyflash.h>
#include "paho_mqtt.h"

#include <MQTT/mqtt.h>


#define DBG_ENABLE
#define DBG_SECTION_NAME "mqtt"
#define DBG_LEVEL DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>

/* 定义 MQTT 客户端环境结构体 */
static MQTTClient client;
static int is_started;
static MQTTConfig mqtt_cfg;


int mqtt_is_connected() {
    return is_started;
}

void mqtt_send_msg(int code, char *msg) {
    char buf[100];
    snprintf(buf, sizeof(buf), "{\"aswcode\":\"%d\",\"aswmsg\":\"%s\"}", code, msg);
    mqtt_publish(buf);
}

// mqtt保存配置到env中
void mqtt_set_conf(struct MQTTConfig cfg) 
{
    ef_set_env("mqtt_uri", &cfg.MQTT_URI);
    ef_set_env("mqtt_clientid", &cfg.MQTT_CLIENTID);
    ef_set_env("mqtt_username", &cfg.MQTT_USERNAME);
    ef_set_env("mqtt_password", &cfg.MQTT_PASSWORD);
    ef_set_env("mqtt_subtopic", &cfg.MQTT_SUBTOPIC);
    ef_set_env("mqtt_pubtopic", &cfg.MQTT_PUBTOPIC);
    ef_set_env("mqtt_willmsg", &cfg.MQTT_WILLMSG);
}

// mqtt从env中读取配置
struct MQTTConfig mqtt_get_conf()
{
    struct MQTTConfig cfg;
    snprintf(cfg.MQTT_URI, sizeof(cfg.MQTT_URI), "%s", ef_get_env("mqtt_uri"));
    snprintf(cfg.MQTT_CLIENTID, sizeof(cfg.MQTT_CLIENTID), "%s", ef_get_env("mqtt_clientid"));
    snprintf(cfg.MQTT_USERNAME, sizeof(cfg.MQTT_USERNAME), "%s", ef_get_env("mqtt_username"));
    snprintf(cfg.MQTT_PASSWORD, sizeof(cfg.MQTT_PASSWORD), "%s", ef_get_env("mqtt_password"));
    snprintf(cfg.MQTT_SUBTOPIC, sizeof(cfg.MQTT_SUBTOPIC), "%s", ef_get_env("mqtt_subtopic"));
    snprintf(cfg.MQTT_PUBTOPIC, sizeof(cfg.MQTT_PUBTOPIC), "%s", ef_get_env("mqtt_pubtopic"));
    snprintf(cfg.MQTT_WILLMSG, sizeof(cfg.MQTT_WILLMSG), "%s", ef_get_env("mqtt_willmsg"));
    // ef_get_env_blob("mqtt_willmsg", &cfg.MQTT_WILLMSG, sizeof(cfg.MQTT_WILLMSG), 0);
    return cfg;
}

// mqtt初始化配置
static void mqtt_conf_init() 
{
    if (ef_get_env_blob("mqtt_uri", &mqtt_cfg.MQTT_URI, sizeof(mqtt_cfg.MQTT_URI), 0) == 0) {
        snprintf(mqtt_cfg.MQTT_URI, sizeof(mqtt_cfg.MQTT_URI), "%s", DEFAULT_MQTT_URI);
    }
    if (ef_get_env_blob("mqtt_clientid", &mqtt_cfg.MQTT_CLIENTID, sizeof(mqtt_cfg.MQTT_CLIENTID), 0) == 0) {
        snprintf(mqtt_cfg.MQTT_CLIENTID, sizeof(mqtt_cfg.MQTT_CLIENTID), "%s", DEFAULT_MQTT_CLIENTID);
    }
    if (ef_get_env_blob("mqtt_username", &mqtt_cfg.MQTT_USERNAME, sizeof(mqtt_cfg.MQTT_USERNAME), 0) == 0) {
        snprintf(mqtt_cfg.MQTT_USERNAME, sizeof(mqtt_cfg.MQTT_USERNAME), "%s", DEFAULT_MQTT_USERNAME);
    }
    if (ef_get_env_blob("mqtt_password", &mqtt_cfg.MQTT_PASSWORD, sizeof(mqtt_cfg.MQTT_PASSWORD), 0) == 0) {
        snprintf(mqtt_cfg.MQTT_PASSWORD, sizeof(mqtt_cfg.MQTT_PASSWORD), "%s", DEFAULT_MQTT_PASSWORD);
    }
    if (ef_get_env_blob("mqtt_subtopic", &mqtt_cfg.MQTT_SUBTOPIC, sizeof(mqtt_cfg.MQTT_SUBTOPIC), 0) == 0) {
        snprintf(mqtt_cfg.MQTT_SUBTOPIC, sizeof(mqtt_cfg.MQTT_SUBTOPIC), "%s", DEFAULT_MQTT_SUBTOPIC);
    }
    if (ef_get_env_blob("mqtt_pubtopic", &mqtt_cfg.MQTT_PUBTOPIC, sizeof(mqtt_cfg.MQTT_PUBTOPIC), 0) == 0) {
        snprintf(mqtt_cfg.MQTT_PUBTOPIC, sizeof(mqtt_cfg.MQTT_PUBTOPIC), "%s", DEFAULT_MQTT_PUBTOPIC);
    }
    if (ef_get_env_blob("mqtt_willmsg", &mqtt_cfg.MQTT_WILLMSG, sizeof(mqtt_cfg.MQTT_WILLMSG), 0) == 0) {
        snprintf(mqtt_cfg.MQTT_WILLMSG, sizeof(mqtt_cfg.MQTT_WILLMSG), "%s", DEFAULT_MQTT_WILLMSG);
    }
    
    LOG_I("");
    LOG_I("===================MQTT CONFIG====================");
    LOG_I("| MQTT_URI\t| %s\t|", mqtt_cfg.MQTT_URI);
    LOG_I("| MQTT_CLIENTID\t| %s\t\t\t|", mqtt_cfg.MQTT_CLIENTID);
    LOG_I("| MQTT_USERNAME\t| %s\t\t\t\t|", mqtt_cfg.MQTT_USERNAME);
    LOG_I("| MQTT_PASSWORD\t| %s\t\t\t|", mqtt_cfg.MQTT_PASSWORD);
    LOG_I("| MQTT_SUBTOPIC\t| %s\t|", mqtt_cfg.MQTT_SUBTOPIC);
    LOG_I("| MQTT_PUBTOPIC\t| %s\t|", mqtt_cfg.MQTT_PUBTOPIC);
    LOG_I("| MQTT_WILLMSG\t| %s\t\t\t|", mqtt_cfg.MQTT_WILLMSG);
    LOG_I("==================================================");
}

/* MQTT 订阅事件自定义回调函数 */
static void mqtt_sub_callback(MQTTClient *c, MessageData *msg_data)
{
    *((char *)msg_data->message->payload + msg_data->message->payloadlen) = '\0';
    LOG_D("mqtt recv [topic]: %.*s", msg_data->topicName->lenstring.len, msg_data->topicName->lenstring.data);
    LOG_D("mqtt recv [payload]: %.*s", msg_data->message->payloadlen, (char *)msg_data->message->payload);

    cJSON *json_data;
    json_data = cJSON_Parse((char *)msg_data->message->payload);

    if (!json_data)
    {
        LOG_D("Error before: [%s]", cJSON_GetErrorPtr());
    }
    else
    {
        cJSON *code = cJSON_GetObjectItem(json_data, "code");
        cJSON *msg = cJSON_GetObjectItem(json_data, "msg");
        // mqtt_code_deal(code, msg);
        mqtt_recv_callback(code, msg);
        cJSON_Delete(json_data);
    }
}
/* MQTT 订阅事件默认回调函数 */
static void mqtt_sub_default_callback(MQTTClient *c, MessageData *msg_data)
{
    *((char *)msg_data->message->payload + msg_data->message->payloadlen) = '\0';
    LOG_D("mqtt sub default callback: %.*s %.*s", msg_data->topicName->lenstring.len,
          msg_data->topicName->lenstring.data, msg_data->message->payloadlen, (char *)msg_data->message->payload);
}
/* MQTT 连接事件回调函数 */
static void mqtt_connect_callback(MQTTClient *c)
{
    is_started = 1;
    LOG_D("inter mqtt_connect_callback!");
}
/* MQTT 上线事件回调函数 */
static void mqtt_online_callback(MQTTClient *c)
{
    LOG_D("inter mqtt_online_callback!");
}
/* MQTT 下线事件回调函数 */
static void mqtt_offline_callback(MQTTClient *c)
{
    is_started = 0;
    LOG_D("inter mqtt_offline_callback!");
}

int mqtt_start()
{
    // mqtt_get_env();
    mqtt_conf_init();
    /* 使用 MQTTPacket_connectData_initializer 初始化 condata 参数 */
    MQTTPacket_connectData condata = MQTTPacket_connectData_initializer;
    //    static char cid[20] = { 0 };
    if (is_started)
    {
        LOG_E("mqtt client is already connected.");
        return -1;
    }
    /* 配置 MQTT 结构体内容参数 */
    {
        client.isconnected = 0;
        client.uri = mqtt_cfg.MQTT_URI;
        /* 产生随机的客户端 ID */
        //        rt_snprintf(MQTT_CLIENTID, sizeof(cid), "rtthread%d", rt_tick_get());
        /* 配置连接参数 */
        memcpy(&client.condata, &condata, sizeof(condata));
        client.condata.clientID.cstring = mqtt_cfg.MQTT_CLIENTID;
        client.condata.keepAliveInterval = 30;
        client.condata.cleansession = 1;
        client.condata.username.cstring = mqtt_cfg.MQTT_USERNAME;
        client.condata.password.cstring = mqtt_cfg.MQTT_PASSWORD;
        /* 配置 MQTT 遗言参数 */
        client.condata.willFlag = 1;
        client.condata.will.qos = 1;
        client.condata.will.retained = 0;
        client.condata.will.topicName.cstring = mqtt_cfg.MQTT_PUBTOPIC;
        client.condata.will.message.cstring = mqtt_cfg.MQTT_WILLMSG;
        /* 分配缓冲区 */
        client.buf_size = client.readbuf_size = 1024;
        client.buf = rt_calloc(1, client.buf_size);
        client.readbuf = rt_calloc(1, client.readbuf_size);
        if (!(client.buf && client.readbuf))
        {
            LOG_E("no memory for MQTT client buffer!");
            return -1;
        }
        /* 设置事件回调函数 */
        client.connect_callback = mqtt_connect_callback;
        client.online_callback = mqtt_online_callback;
        client.offline_callback = mqtt_offline_callback;
        /* 设置订阅表和事件回调函数*/
        client.messageHandlers[0].topicFilter = rt_strdup(mqtt_cfg.MQTT_SUBTOPIC);
        client.messageHandlers[0].callback = mqtt_sub_callback;
        client.messageHandlers[0].qos = QOS1;
        /* 设置默认的订阅主题*/
        client.defaultMessageHandler = mqtt_sub_default_callback;
    }
    /* 运行 MQTT 客户端 */
    paho_mqtt_start(&client);
    return 0;
}
MSH_CMD_EXPORT(mqtt_start, mqtt start);
/* 该函数用于停止 MQTT 客户端并释放内存空间 */
int mqtt_stop()
{
    is_started = 0;
    return paho_mqtt_stop(&client);
}
/* 该函数用于发送数据到指定 topic */
int mqtt_publish(const char *msg_str)
{
    if (is_started == 0)
    {
        LOG_E("mqtt client is not connected.");
        return -1;
    }
    LOG_I("");
    LOG_I("========================MQTT Publish======================");
    LOG_I("| Topic\t\t| %s\t\t|", mqtt_cfg.MQTT_PUBTOPIC);
    LOG_I("| Payload\t| %s\t|", msg_str);
    LOG_I("==========================================================");
    paho_mqtt_publish(&client, QOS1, mqtt_cfg.MQTT_PUBTOPIC, msg_str);
    // rt_thread_mdelay(200);
    return 0;
}
/* MQTT 新的订阅事件自定义回调函数 */
static void mqtt_new_sub_callback(MQTTClient *client, MessageData *msg_data)
{
    *((char *)msg_data->message->payload + msg_data->message->payloadlen) = '\0';
    LOG_D("mqtt new subscribe callback: %.*s %.*s", msg_data->topicName->lenstring.len,
          msg_data->topicName->lenstring.data, msg_data->message->payloadlen, (char *)msg_data->message->payload);
}
/* 该函数用于订阅新的 Topic */
int mqtt_subscribe(const char *topic)
{
    if (is_started == 0)
    {
        LOG_E("mqtt client is not connected.");
        return -1;
    }
    return paho_mqtt_subscribe(&client, QOS0, topic, mqtt_new_sub_callback);
}
/* 该函数用于取消订阅指定的 Topic */
int mqtt_unsubscribe(const char *topic)
{
    if (is_started == 0)
    {
        LOG_E("mqtt client is not connected.");
        return -1;
    }
    return paho_mqtt_unsubscribe(&client, topic);
}

void test_ex_sensor(void)
{
    char ex_sensor_send_str[] = "{\"code\":\"1051\",\"msg\":[\"98.123\",\"23.1\",\"30.1\"]}";
    cJSON *json_data;
    json_data = cJSON_Parse(ex_sensor_send_str);

    if (!json_data)
    {
        LOG_D("Error before: [%s]", cJSON_GetErrorPtr());
    }
    else
    {
        cJSON *code = cJSON_GetObjectItem(json_data, "code");
        cJSON *msg = cJSON_GetObjectItem(json_data, "msg");
        // mqtt_code_deal(code, msg);
        mqtt_recv_callback(code, msg);
        cJSON_Delete(json_data);
    }
}
MSH_CMD_EXPORT(test_ex_sensor, test_ex_sensor);

void get_env(void)
{
    char ex_sensor_send_str[] = "{\"code\":\"1050\",\"msg\":\"00\"}";
    cJSON *json_data;
    json_data = cJSON_Parse(ex_sensor_send_str);

    if (!json_data)
    {
        LOG_D("Error before: [%s]", cJSON_GetErrorPtr());
    }
    else
    {
        cJSON *code = cJSON_GetObjectItem(json_data, "code");
        cJSON *msg = cJSON_GetObjectItem(json_data, "msg");
        // mqtt_code_deal(code, msg);
        mqtt_recv_callback(code, msg);
        cJSON_Delete(json_data);
    }
}
MSH_CMD_EXPORT(get_env, get_env);


// #ifdef FINSH_USING_MSH
// MSH_CMD_EXPORT(mqtt_set_env, config mqtt and save to easyflash);
// #endif /* FINSH_USING_MSH */
